package com.net.xpay.openapi.aop;


import com.net.xpay.openapi.protocol.OpenApiBase;
import com.net.xpay.openapi.protocol.OpenApiProtocol;
import com.net.xpay.openapi.protocol.OpenApiResult;
import com.net.xpay.openapi.protocol.OpenApiSignature;
import com.net.common.exception.BusinessException;
import com.net.xpay.common.domain.User;
import com.net.xpay.common.domain.UserShard;
import com.net.xpay.common.domain.openapi.OpenApp;
import com.net.xpay.common.manager.UserManager;
import com.net.xpay.common.manager.UserShardManager;
import com.net.xpay.common.manager.openapi.OpenAppManager;
import com.net.xpay.common.service.ApiMonitorService;
import com.net.xpay.core.constant.PoseidonErrorCode;
import com.net.shard.ShardUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * 对controller层做增强操作、请求参数签名验证、响应参数签名、设置分库信息等
 */
@Slf4j
@Aspect
@Component
public class OpenApiControllerAop {

    @Autowired
    private OpenApiBase openApiBase;

    @Autowired
    private UserShardManager userShardManager;

    @Autowired
    private UserManager userManager;

    @Autowired
    private OpenAppManager openAppManager;

    @Autowired
    private ApiMonitorService apiMonitorService;


    @Pointcut(value = "@annotation(com.net.xpay.openapi.aop.OpenApi)")
    public void controllerMethods() {}

    @Around("controllerMethods()")
    public Object profile(ProceedingJoinPoint pjp) throws Throwable {

        Object[] args = pjp.getArgs();
        if (args != null) {
            for (Object object : args) {
                if (object instanceof OpenApiProtocol) {
                    OpenApiProtocol protocol = (OpenApiProtocol)object;
                    // 获取到路由信息
                    ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                    assert requestAttributes != null;
                    HttpServletRequest request = requestAttributes.getRequest();
                    try {
                        //验证签名和ip白名单
                        OpenApp openApp = openApiBase.checkProtocol(request, protocol);
                        //设置分库信息
                        User user = userManager.getById(openApp.getUserId());
                        UserShard userShard = userShardManager.getById(user.getId());
                        ShardUtil.setShardContext(userShard.getShardId());

                        Object proceed = pjp.proceed();
                        OpenApiResult ret = (OpenApiResult) proceed;
                        Map<String, String> params = new HashMap<>();
                        params.put("data", ret.getData());
                        params.put("resultCode", ret.getResultCode());
                        params.put("resultMessage", ret.getResultMessage());
                        String signCheckContent = OpenApiSignature.getSignCheckContent(params);
                        String sign = OpenApiSignature.rsaSign(signCheckContent, openApp.getPrivateKey(), "UTF-8", "RSA2");
                        ret.setSign(sign);
                        return ret;
                    } catch (Exception e) {
                        OpenApiResult<String> ret;
                        log.info("encounter business exception|url={}", request.getRequestURI(), e);
                        //添加异常统计
                        try {
                            String api = request.getRequestURI();
                            apiMonitorService.addErrorData(api);
                        } catch (Exception ex) {
                            log.error("apiMonitorService.addErrorData error|api={}", request.getRequestURI(), ex);
                        }
                        if (e instanceof BusinessException) {
                            BusinessException se = (BusinessException) e;
                            log.info("encounter business exception|code={}|message={}|url={}", se.getErrorCode(), se.getErrorMessage(), request.getRequestURI());
                            ret = new OpenApiResult<>(se.getErrorCode(), se.getErrorMessage());
                        } else {
                            ret = new OpenApiResult<>(PoseidonErrorCode.UNKNOWN_ERROR, "未知错误");
                        }
                        OpenApp openApp = openAppManager.getById(Long.valueOf(protocol.getAppId()));
                        if (openApp == null) {
                            //应用不存在就不用签名了
                            return ret;
                        }
                        Map<String, String> params = new HashMap<>();
                        params.put("resultCode", ret.getResultCode());
                        params.put("resultMessage", ret.getResultMessage());
                        String signCheckContent = OpenApiSignature.getSignCheckContent(params);
                        String sign = OpenApiSignature.rsaSign(signCheckContent, openApp.getPrivateKey(), "UTF-8", "RSA2");
                        ret.setSign(sign);
                        return ret;
                    } finally {
                        //清除分库信息
                        ShardUtil.cleanShardContext();
                    }
                }
            }
            return pjp.proceed();
        } else {
            return pjp.proceed();
        }
    }
}
